Para esta tarea hemos escogido una base de datos relativa a apartamentos Airbnb de Madrid procedentes de la plataforma Inside Airbnb. Se trata de un portal en el que mensualmente se publican datos actualizados sobre dichos apartamentos. Nuestros datos proceden de una muestra publicada en diciembre de 2021, por lo que son bastante recientes.
Nuestro conjunto de datos partía de una muestra de tamaño \(n = 17831\) apartamentos, habitaciones y anuncios del portal Airbnb, y de más de \(p = 80\) variables categóricas (multi-estado y binarias) y numéricas (continuas y discretas). Hemos descartado aquellas variables con más porcentaje de datos faltantes (NA) y finalmente nos hemos quedado con una tamaño muestral de \(n = 5362\) y un total de \(p = 81\) variables.
Las variables de nuestra base de datos son:Para realizar la mayor parte de la limpieza hemos usado R. Hemos descartado aquellas variables que contenían mayor proporción de NA’s y convertido algunas variables como amenities. Esta variable, que tomaremos como ejemplo, devolvía para cada apartamento, un string con las amenidades del apartamento en este formato:
"[\"Hot water\", \"Iron\", \"Washer\", \"Air conditioning\", \"Cable TV\", \"TV with standard cable\", \"Heating\", \"Elevator\", \"Dryer\", \"Shampoo\", \"Host greets you\", \"Luggage dropoff allowed\", \"Wifi\", \"Hangers\", \"Essentials\", \"Dedicated workspace\", \"Long term stays allowed\", \"Hair dryer\", \"First aid kit\", \"Kitchen\"]"
Hemos convertido cada valor de todos los strings en variables binarias (true o false), siendo true si la palabra aparecía en el string de dicho apartamento y false si no, ya que no había otra manera de extraer información. Posteriormente hemos eliminado aquellas variables binarias que tenían una proporción muy alta de un tipo de respuesta (por ejemplo 99.93% true, 0.07 false).
A continuación el código para la limpieza de datos:
Primero leemos los datos que hemos limpiado previamente, MATLAB, nos convierte los nombres de columnas a nombres válidos directamente.
Separamos variables numéricas y categóricas:
airbnb_data = readtable('datos_limpios.csv');
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before creating variable names for the table. The original column headers are saved in the VariableDescriptions property.
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names.
Separamos variables numéricas y categóricas
variables_numericas = airbnb_data(:, vartype('numeric'));
Convertimos las variables tipo cell en categorical, ya que nos facilitará el trabajo posteriormente.
variables_cell = airbnb_data(:, vartype("cell"));
variables_categoricas = array2table(zeros(size(variables_cell)));
variables_categoricas.Properties.VariableNames = variables_cell.Properties.VariableNames;
variables_categoricas = convertvars(variables_cell, variables_categoricas.Properties.VariableNames,'categorical');
Convertimos la tabla que contiene las variables numéricas en una matriz, y extraemos los nombres de las correspondientes variables:
X_numericas = table2array(variables_numericas);
nombres_variables_numericas = categorical(variables_numericas.Properties.VariableNames);
Realizamos tablas y diagramas de frecuencias
Primeramente dividimos entre variables continuas y discretas:
continuas = [1, 3, 4, 9, 16:22];
discretas = setdiff(1:size(X_numericas, 2), continuas);
X_continuas = X_numericas(:, continuas);
nombres_variables_continuas = nombres_variables_numericas(continuas);
X_discretas = X_numericas(:, discretas);
nombres_variables_discretas = nombres_variables_numericas(discretas);
Ahora nos centraremos únicamente en variables continuas, ya que los métodos que usaremos requieren suponer una hipótesis de normalidad. Realizamos un gplotmatrix() para ver qué aspecto tienen las variables continuas:
%plot inline
figure
plotmatrix(X_continuas)
png
Según lo que podemos ver, los datos no parece que sigan una normal multivariante, ya que vemos que hay fuertes asimetrías. Obtenemos el vector de medias muestrales, la matriz de covarianzas muestral y de correlaciones:
Usamos la función plot_map que nos permite ver la matriz de correlaciones de manera más visual:
%%file plot_map.m
function fig_h = plot_map(map,label,int,ind)
% Plot color map.
%
% plot_map(map) % minimum call
% plot_map(map,label) % complete call
%
%
% INPUTS:
%
% map: (MxM) matrix with values in the [0,1] interval.
%
% label: (Mx1) name of the variables (numbers are used by default)
%
% int: (2x1) color interval ([-1;1] by default)
%
% ind: (Lx1) color distribution ([0:.2:0.79 0.8:0.04:1]' by default);
%
% OUTPUTS:
%
% fig_h: (1x1) figure handle.
%
%
% EXAMPLE OF USE: Random data
%
% X = simuleMV(20,10,8);
% plot_map(corr(X));
%
%
% coded by: Jose Camacho Paez (josecamacho@ugr.es)
% Alejandro Perez Villegas (alextoni@gmail.com)
% last modification: 08/Apr/20
%
% Copyright (C) 2020 University of Granada, Granada
% Copyright (C) 2020 Jose Camacho Paez, Alejandro Perez Villegas
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%% Parameters checking
% Set default values
routine=dbstack;
assert (nargin >= 1, 'Error in the number of arguments. Type ''help %s'' for more info.', routine(1).name);
M = size(map,2);
if nargin < 2 || isempty(label), label= 1:M; end
if nargin < 3 || isempty(int), int = [-1;1]; end;
if nargin < 4 || isempty(ind), ind = [0:.2:0.79 0.8:0.04:1]'; end;
% Convert row arrays to column arrays
if size(label,1) == 1, label = label'; end;
% Convert int arrays to str
if ~isempty(label) && isnumeric(label),
vecn = label;
veci = 1:length(vecn);
if length(label)>2,
max_lab = 30; % limit the number of labels displayed
ini = 2;
stepN = [];
while isempty(stepN),
lenv = length(vecn(ini:end));
div = 1:(lenv-1);
div = div(rem(lenv,div)==0);
stepN = div(find(div>lenv/max_lab,1));
ini = ini+1;
end
veci = 1:(lenv+ini-2);
veci = veci(round([1 (ini-2+stepN):stepN:end]));
end
for i=veci,
labele{i} = num2str(vecn(i));
end
label=labele';
end
% Convert char arrays to cell
if ischar(label), label = cellstr(label); end;
%% Main code
fig_h=figure;
map3 = [map map(:,end);map(end,:) map(end,end)];
sur_h=surface((1:M+1)'*ones(1,M+1),ones(M+1,1)*(1:M+1),map3);
if M < 100
set(sur_h,'EdgeColor',[0.95 0.95 0.95]);
else
set(sur_h,'EdgeColor','none');
end
% Label font size
axes_h = get(sur_h,'Parent');
if ~isempty(label)
label_length = max(cellfun('length', label));
label_size = 300/(length(find(~cellfun('isempty', label)))*label_length);
set(axes_h, 'FontSize', max(min(18,round(label_size)), 14));
end
% Set axis properties
set(axes_h,'Box','on');
set(axes_h,'XAxisLocation','top');
set(axes_h,'YDir','reverse');
if ~isempty(label)
stepY = ceil(0.05*M/label_size);
stepX = ceil(0.2*M/label_size);
if stepX==1,
set(axes_h,'XTick',(1:M)+0.5);
set(axes_h,'XTickLabel',label);
else
set(axes_h,'XTickLabel','');
end
if stepY==1,
set(axes_h,'YTick',(1:M)+0.5);
set(axes_h,'YTickLabel',label);
else
set(axes_h,'YTickMode','auto');
end
end
% Resize axes position
pos = get(axes_h, 'Position');
set(axes_h,'Position',[pos(1) pos(2)/2 pos(3) pos(4)])
% Set colors
if int(1)<0,
set(fig_h,'Colormap',[[ind;ones(length(ind),1)] [ind;flipud(ind)] [ones(length(ind),1);flipud(ind)]])
else
set(fig_h,'Colormap',[[ones(length(ind),1)] [flipud(ind)] [flipud(ind)]])
end
caxis(int);
if find(map>0 & map<=1)
c_h=colorbar;
set(c_h,'FontSize',14);
end
axis([1,M+1,1,M+1]);
Created file 'C:\Users\marct\Documents\UNI_ESTADISTICA\3o\SEGUNDO CUATRIMESTRE\ANÁLISIS MULTIVARIANTE\TRABAJOS\DATOS\Airbnb Madrid\plot_map.m'.
m = mean(X_continuas)
S = cov(X_continuas, 1)
R = corr(X_continuas)
plot_map(R, char(nombres_variables_continuas.'))
m =
0.8741 40.4203 -3.6954 119.3581 4.6562 4.7429 4.6990 4.8045 4.8003 4.8063 4.6133
S =
1.0e+05 *
0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000
-0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000
-0.0000 -0.0000 -0.0000 1.0428 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000
0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
R =
1.0000 -0.0320 -0.0629 -0.0106 0.0113 0.0344 0.0553 -0.0016 0.0050 0.0682 0.0373
-0.0320 1.0000 0.2889 -0.0500 0.0513 0.0407 0.0379 0.0394 0.0365 0.0788 0.0165
-0.0629 0.2889 1.0000 -0.0324 0.0591 0.0495 0.0384 0.0397 0.0451 -0.1120 0.0358
-0.0106 -0.0500 -0.0324 1.0000 -0.0146 -0.0051 -0.0032 -0.0109 -0.0207 0.0101 -0.0132
0.0113 0.0513 0.0591 -0.0146 1.0000 0.8323 0.7846 0.7017 0.7655 0.4916 0.8478
0.0344 0.0407 0.0495 -0.0051 0.8323 1.0000 0.7202 0.7071 0.7355 0.4895 0.7670
0.0553 0.0379 0.0384 -0.0032 0.7846 0.7202 1.0000 0.5984 0.6252 0.4500 0.7498
-0.0016 0.0394 0.0397 -0.0109 0.7017 0.7071 0.5984 1.0000 0.7711 0.5022 0.6548
0.0050 0.0365 0.0451 -0.0207 0.7655 0.7355 0.6252 0.7711 1.0000 0.4816 0.6831
0.0682 0.0788 -0.1120 0.0101 0.4916 0.4895 0.4500 0.5022 0.4816 1.0000 0.4883
0.0373 0.0165 0.0358 -0.0132 0.8478 0.7670 0.7498 0.6548 0.6831 0.4883 1.0000
ans =
Figure (1) with properties:
Number: 1
Name: ''
Color: [0.9400 0.9400 0.9400]
Position: [488 342 560 420]
Units: 'pixels'
Use GET to show all properties
png
Podemos ver claramente que las variables relacionadas con la puntuación del apartamento (ratings), tienen una gran asimetría a la izquierda, es decir que en general el consumidor suele poner buenas reseñas. Además, podemos ver que las variables más correlacionadas son aquellas relacionadas con el rating del apartamento.
Hemos realizado algunos mapas, mediante la herramienta QGIS, para analizar visualmente los datos, puesto que se trata de datos geográficos: